Home:ALL Converter>Connecting a sink of BLoC with another BLoC

Connecting a sink of BLoC with another BLoC

Ask Time:2018-11-12T07:42:18         Author:S.D.

Json Formatter

I am using the BLoC pattern as described at the Google IO talk.

I have a simple BLoC which is used to display a alert in the UI whenever a string is added to messageSink:

class AlertBloc {
  final _message = BehaviorSubject<String>();

  AlertBloc() {}

  Stream<String> get message => _message.stream;

  Sink<String> get messageSink => _message.sink;

  void dispose() {
    _message.close();   }
}

Elsewhere in the app, I have another BLoC which needs to add a string to messageSink, when a certain condition is met.

I noticed it is not a good idea to provide the whole BLoC from the Google I/O repo for the talk, and they provide advice for connecting a stream from a BLoC to another BLoC sink:

Note that we are not providing [CartBloc] to the [ProductSquareBloc] directly, although it would be easier to implement. BLoCs should not depend on other BLoCs (separation of concerns). They can only communicate with each other using streams. In this case, the [CartBloc.items] output plugs into the [ProductSquareBloc.cartItems] input.

My question is how to connect a sink from a BLoC to another BLoC stream?

Author:S.D.,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/53254371/connecting-a-sink-of-bloc-with-another-bloc
Alex Semeniuk :

Here is a simple example for you. Imagine the following two BLoCs:\n\nThe first one exposes a Stream and populates it with some values:\n\nclass ProducerBLoC {\n\n //Controller is private - you do not want to expose it\n final StreamController<int> _productionController = StreamController<int>();\n //Instead, you expose a stream\n Stream<int> get production => _productionController.stream;\n\n //This method generates some values and puts them to stream\n void produceValue() {\n _productionController.sink.add(1);\n _productionController.sink.add(2);\n _productionController.sink.add(3);\n }\n\n //Don't forget to close your controllers\n void dispose() {\n _productionController.close();\n }\n}\n\n\nThe other one exposes a Sink and processes values that are put into it.\n\nclass ConsumerBLoC {\n\n //Controller is private - you do not want to expose it\n final StreamController<int> _consumptionController = StreamController<int>();\n //Instead, you expose a sink\n StreamSink<int> get consumption => _consumptionController.sink;\n\n //In class constructor we start listening to the stream of values\n ConsumerBLoC() {\n _consumptionController.listen((value) {_consumeValue(value);} );\n //or simply: _consumptionController.listen(_consumeValue); //theese are the same\n }\n\n //This method generates some values and puts them to stream\n void consumeValue(int value) {\n //Do something with the value\n print('Value processed: $value');\n }\n\n //Don't forget to close your controllers\n void dispose() {\n _consumptionController.close();\n }\n}\n\n\nNow, the task is to connect production stream to consumption sink. As you have correctly noticed, you do not want for any of two BLoCs to know anything about existence of the other one. So none of the two should hold references to the other one or even create instances of another one. Instead, you connect them using your Widget class:\n\n//Define some widget to represent main screen of your application\nclass MainScreen extends StatefulWidget {\n\n @override\n State<StatefulWidget> createState() => _MainScreenState();\n}\n\n//And define a state for this widget (state does not need to be public)\nclass _MainScreenState extends State<MainScreen> {\n\n //You define both blocks here\n ProducerBLoC _producer = new ProducerBLoC();\n ConsumerBLoC _consumer = new ConsumerBLoC();\n\n //Now, either do it in _MainScreenState constructor, or in the initState() method\n @override\n void initState() {\n super.initState();\n\n //Connect production stream with consumption sink\n _producer.production.listen((value) => _consumer.consumption.add(value));\n //Or, beautifully: _producer.production.pipe(_consumer.consumption);\n }\n\n @override\n Widget build(BuildContext context) {\n //The exact implementation does not matter in current context\n }\n\n //And don't forget to close your controllers\n @override\n dispose() {\n super.dispose();\n _producer.dispose();\n _consumer.dispose();\n }\n\n}\n\n\nThis way, any value generated by ProducerBLoC will immediately be consumed by ConsumerBLoC. And, what's the most important, - both BLoCs are completely independent from one another!",
2019-08-19T15:31:18
yy